package fr.utbm.gi.vi51.project.formations;

import java.util.ArrayList;
import java.util.Collection;

import javax.vecmath.Point2d;

public class LineFormation extends FormationBody {

	private static final int INTER_SLOT_SPACE = 24;
	private static final int RATIO = 2;
	private static int UNITS_PER_LANE;

	public LineFormation(FormationOrientation orientation) {
		super();
		this.orientation = orientation;
	}

	@Override
	public Collection<FormationSlot> scaleAt(int numberOfSlots, Point2d leaderPosition) {
		LineFormation.UNITS_PER_LANE = (int) (RATIO * Math.sqrt(numberOfSlots / RATIO));
		ArrayList<FormationSlot> formationSlots = new ArrayList<>();
		if (numberOfSlots > 1) {
			// Make a leader
			FormationSlot leaderSlot = new FormationSlot(null, this, 0, leaderPosition.getX(), leaderPosition.getY(), 0);
			formationSlots.add(leaderSlot);
			// Count the number of lanes
			int laneCount = (numberOfSlots % UNITS_PER_LANE == 0 ? numberOfSlots / UNITS_PER_LANE : numberOfSlots
					/ UNITS_PER_LANE + 1);
			switch (this.orientation) {
			case NORTH:
				// Add lanes in front of the leader first
				for (int lane = 1; lane < laneCount; lane++) {
					// Slot in the middle of the lane
					FormationSlot middleSlot = new FormationSlot(leaderSlot, this, UNITS_PER_LANE * (lane - 1) + 1, 0,
							-INTER_SLOT_SPACE * lane, 0);
					formationSlots.add(middleSlot);

					// Others slots
					FormationSlot newSlot;
					int distance = 1;
					for (int i = 1; i < UNITS_PER_LANE; i++) {
						if (i % 2 == 1) {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i,
									-INTER_SLOT_SPACE * distance, 0, 0);
						} else {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i,
									INTER_SLOT_SPACE * distance, 0, 0);
							distance++;
						}
						formationSlots.add(newSlot);
					}
				}
				// Then create leader lane
				int distanceNorth = 1;
				for (int i = UNITS_PER_LANE * (laneCount - 1) + 1; i < numberOfSlots; i++) {
					FormationSlot newSlot;
					if (i % 2 == (UNITS_PER_LANE * (laneCount - 1) + 1) % 2) {
						newSlot = new FormationSlot(leaderSlot, this, i, -INTER_SLOT_SPACE * distanceNorth, 0, 0);
					} else {
						newSlot = new FormationSlot(leaderSlot, this, i, INTER_SLOT_SPACE * distanceNorth, 0, 0);
						distanceNorth++;
					}
					formationSlots.add(newSlot);
				}
				break;
			case SOUTH:
				// Add lanes in front of the leader first
				for (int lane = 1; lane < laneCount; lane++) {
					// Slot in the middle of the lane
					FormationSlot middleSlot = new FormationSlot(leaderSlot, this, UNITS_PER_LANE * (lane - 1) + 1, 0,
							INTER_SLOT_SPACE * lane, 0);
					formationSlots.add(middleSlot);

					// Others slots
					FormationSlot newSlot;
					int distance = 1;
					for (int i = 1; i < UNITS_PER_LANE; i++) {
						if (i % 2 == 1) {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i,
									-INTER_SLOT_SPACE * distance, 0, 0);
						} else {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i,
									INTER_SLOT_SPACE * distance, 0, 0);
							distance++;
						}
						formationSlots.add(newSlot);
					}
				}
				// Then create leader lane
				int distanceSouth = 1;
				for (int i = UNITS_PER_LANE * (laneCount - 1) + 1; i < numberOfSlots; i++) {
					FormationSlot newSlot;
					if (i % 2 == (UNITS_PER_LANE * (laneCount - 1) + 1) % 2) {
						newSlot = new FormationSlot(leaderSlot, this, i, -INTER_SLOT_SPACE * distanceSouth, 0, 0);
					} else {
						newSlot = new FormationSlot(leaderSlot, this, i, INTER_SLOT_SPACE * distanceSouth, 0, 0);
						distanceSouth++;
					}
					formationSlots.add(newSlot);
				}
				break;
			case WEST:
				// Add lanes in front of the leader first
				for (int lane = 1; lane < laneCount; lane++) {
					// Slot in the middle of the lane
					FormationSlot middleSlot = new FormationSlot(leaderSlot, this, UNITS_PER_LANE * (lane - 1) + 1,
							-INTER_SLOT_SPACE * lane, 0, 0);
					formationSlots.add(middleSlot);

					// Others slots
					FormationSlot newSlot;
					int distanceWest = 1;
					for (int i = 1; i < UNITS_PER_LANE; i++) {
						if (i % 2 == 1) {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i, 0,
									-INTER_SLOT_SPACE * distanceWest, 0);
						} else {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i, 0,
									INTER_SLOT_SPACE * distanceWest, 0);
							distanceWest++;
						}
						formationSlots.add(newSlot);
					}
				}
				// Then create leader lane
				int distanceWest = 1;
				for (int i = UNITS_PER_LANE * (laneCount - 1) + 1; i < numberOfSlots; i++) {
					FormationSlot newSlot;
					if (i % 2 == (UNITS_PER_LANE * (laneCount - 1) + 1) % 2) {
						newSlot = new FormationSlot(leaderSlot, this, i, 0, -INTER_SLOT_SPACE * distanceWest, 0);
					} else {
						newSlot = new FormationSlot(leaderSlot, this, i, 0, INTER_SLOT_SPACE * distanceWest, 0);
						distanceWest++;
					}
					formationSlots.add(newSlot);
				}
				break;
			default:
				// Add lanes in front of the leader first
				for (int lane = 1; lane < laneCount; lane++) {
					// Slot in the middle of the lane
					FormationSlot middleSlot = new FormationSlot(leaderSlot, this, UNITS_PER_LANE * (lane - 1) + 1,
							INTER_SLOT_SPACE * lane, 0, 0);
					formationSlots.add(middleSlot);

					// Others slots
					FormationSlot newSlot;
					int distanceEast = 1;
					for (int i = 1; i < UNITS_PER_LANE; i++) {
						if (i % 2 == 1) {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i, 0,
									-INTER_SLOT_SPACE * distanceEast, 0);
						} else {
							newSlot = new FormationSlot(middleSlot, this, UNITS_PER_LANE * (lane - 1) + 1 + i, 0,
									INTER_SLOT_SPACE * distanceEast, 0);
							distanceEast++;
						}
						formationSlots.add(newSlot);
					}
				}
				// Then create leader lane
				int distanceEast = 1;
				for (int i = UNITS_PER_LANE * (laneCount - 1) + 1; i < numberOfSlots; i++) {
					FormationSlot newSlot;
					if (i % 2 == (UNITS_PER_LANE * (laneCount - 1) + 1) % 2) {
						newSlot = new FormationSlot(leaderSlot, this, i, 0, -INTER_SLOT_SPACE * distanceEast, 0);
					} else {
						newSlot = new FormationSlot(leaderSlot, this, i, 0, INTER_SLOT_SPACE * distanceEast, 0);
						distanceEast++;
					}
					formationSlots.add(newSlot);
				}
				break;
			}
		}
		return formationSlots;
	}

}
